﻿Namespace EIB.Bus.Addressing
    Public NotInheritable Class EIBGroupAddress
        Inherits EIBAddress

        Public Shared Invalid As New EIBGroupAddress("0/0/0")


        Sub New()
            _address = Invalid._address
        End Sub

        Sub New(address As UInt16)
            _address = address
        End Sub

        Sub New(main As UInt16, medium As UInt16, [sub] As UInt16)
            ParseFromAddress3(main, medium, [sub])
        End Sub

        Sub New(main As UInt16, [sub] As UInt16)
            ParseFromAddress2(main, [sub])
        End Sub

        Sub New(data As Byte())
            If data.Length <> 2 Then Throw New ArgumentException("Argument value not valid. Data must be 2 byte long.", "data")

            ParseFromAddress2((data(0) And &H78) >> 3, ((data(0) And &H7) << 8) + data(1))
        End Sub

        Sub New(address As String)
            Dim s = address.Split("/")

            If s.Length = 2 Then
                Dim main, [sub] As UInt16
                If UInt16.TryParse(s(0), main) AndAlso UInt16.TryParse(s(1), [sub]) Then
                    ParseFromAddress2(main, [sub])
                Else
                    Throw New ArgumentException("Argument value not valid. Address parts must be numeric.", "address")
                End If
            ElseIf s.Length = 3 Then
                Dim main, medium, [sub] As UInt16
                If UInt16.TryParse(s(0), main) AndAlso UInt16.TryParse(s(1), medium) AndAlso UInt16.TryParse(s(2), [sub]) Then
                    ParseFromAddress3(main, medium, [sub])
                Else
                    Throw New ArgumentException("Argument value not valid. Address parts must be numeric.", "address")
                End If
            Else
                Throw New ArgumentException("Agument value not valid. String must have format '#/#/#' or '#/#'.", "address")
            End If
        End Sub


        Private Sub ParseFromAddress2(main As UInt16, [sub] As UInt16)
            If main > &HF Then Throw New ArgumentException("Argument value not valid.", "main")
            If [sub] > &H7FF Then Throw New ArgumentException("Argument value not valid.", "sub")

            _address = (main << 11) + [sub]
        End Sub

        Private Sub ParseFromAddress3(main As UInt16, medium As UInt16, [sub] As UInt16)
            If main > &HF Then Throw New ArgumentException("Argument value not valid.", "main")
            If medium > &H7 Then Throw New ArgumentException("Argument value not valid.", "medium")
            If [sub] > &HFF Then Throw New ArgumentException("Argument value not valid.", "sub")

            _address = (main << 11) + (medium << 8) + [sub]
        End Sub


        Public Overrides Function ToString() As String
            Return ToString("3")
        End Function

        Public Overloads Function ToString(format As String) As String
            Select Case format
                Case "2", "#/#"
                    Return String.Format("{0}/{1}", ((_address And &H7800) >> 11), _address And &H7FF)
                Case "3", "#/#/#"
                    Return String.Format("{0}/{1}/{2}", ((_address And &H7800) >> 11), ((_address And &H700) >> 8), _address And &HFF)
                Case Else
                    Throw New ArgumentException("Argument value not valid.", "format")
            End Select
        End Function


        Private Function GetMain() As UInt16
            Return (_address And &H7800) >> 11
        End Function

        Private Function GetMedium() As UInt16
            Return (_address And &H700) >> 8
        End Function

        Private Function GetSub() As UInt16
            Return _address And &HFF
        End Function


        Public Shared Operator +(a1 As EIBGroupAddress, a2 As EIBGroupAddress) As EIBGroupAddress
            Return New EIBGroupAddress(a1.GetMain + a2.GetMain, a1.GetMedium + a2.GetMedium, a1.GetSub + a2.GetSub)
        End Operator

        Public Shared Operator -(a1 As EIBGroupAddress, a2 As EIBGroupAddress) As EIBGroupAddress
            Return New EIBGroupAddress(a1.GetMain - a2.GetMain, a1.GetMedium - a2.GetMedium, a1.GetSub - a2.GetSub)
        End Operator


        Public Overloads Shared Function IsInvalid(address As EIBGroupAddress) As Boolean
            Return address._address = Invalid._address
        End Function

        Public Overrides Function IsInvalid() As Boolean
            Return _address = Invalid._address
        End Function

        Public Shared Function IsValidAddress(main As UInt16, [sub] As UInt16) As Boolean
            Return Not main > &HF AndAlso Not [sub] > &H7FF
        End Function

        Public Shared Function IsValidAddress(main As UInt16, medium As UInt16, [sub] As UInt16) As Boolean
            Return Not main > &HF AndAlso Not medium > &H7 AndAlso Not [sub] > &HFF
        End Function
    End Class
End Namespace